/*************************************************************************
    > File Name: copy.c
    > Author: ma6174
    > Mail: ma6174@163.com 
    > Created Time: 2022年10月27日 星期四 16时12分48秒
 ************************************************************************/

#include"buffer.h"
//获取文件大小
//int flag = 0;//标志要拷贝文件的类型：1目录，0文件
size_t getFileSize(int fd){
	struct stat st;
	fstat(fd, &st);
	return st.st_size;
}

//线程拷贝函数
void *thread_copy(void *arg)
{
	struct thread_block *block = (struct thread_block *)arg;
	char buf[BUFSIZE];
	size_t count = block->begin;
	lseek(block->infd, block->begin, SEEK_SET);
	lseek(block->outfd, block->begin, SEEK_SET);
	int read_size;
	int write_size;
	while (count < block->end) {
		if ((read_size = read(block->infd, buf, BUFSIZE)) == -1) {
			perror("read error");
			exit(1);
		}
		if (read_size == 0) {
			break;
		}
		count += read_size;
		char *pwrite = buf;
		while ((write_size = write(block->outfd, buf, read_size)) != 0) {
			if (write_size == -1) {
				perror("write error");
				exit(1);
			}
			if (write_size == read_size) break;
			else if (write_size > 0) {
				pwrite += write_size;
				read_size -= write_size;
			}
		}
	
	}
	pthread_exit(NULL);
}

//拷贝文件(多线程)
//src 源文件 dst目标文件
void copyfile(char *src, char *dst)
{
	int infd = open(src, O_RDONLY);
	int outfd = open(dst, O_RDWR|O_TRUNC|O_CREAT, 0644);

	if (infd == -1 || outfd == -1) {
		perror("open error");
		exit(1);
	}
	
	size_t file_size = getFileSize(infd);
	int thread_size = THREADS_COUNT;
	struct thread_block *blocks = (struct thread_block *)malloc(sizeof(struct thread_block) * thread_size);
	int per = file_size / thread_size;
	for (int i = 0; i < thread_size; i++) {
		blocks[i].infd = infd;
		blocks[i].outfd = outfd;
		blocks[i].begin = i * per;
		if (i == thread_size) {
			blocks[i].end = file_size;
		} else {
			blocks[i].end = blocks[i].begin + per;
		}
	}

	pthread_t ptid[thread_size];
	//创建线程
	for (int i = 0; i < thread_size; i++) {
		pthread_create(&ptid[i], NULL, thread_copy, &(blocks[i]));
	}

	for (int i = 0; i < thread_size; i++) {
		pthread_join(ptid[i], NULL);
	}

	free(blocks);
	close(infd);
	close(outfd);
//	printf("Copy successfully \n");
}
//*****
//拷贝函数
void copy(char *src, char *dst)
{
	if (flag == 0) {
		copyfile(src, dst);
		flag = -1;
		return ;
	}
	if (flag == 1 || flag == -1) {
		DIR *dir = opendir(src);
		if (dir == NULL) {
			perror("opendir error");
			exit(1);
		}
		if (access(dst, F_OK) == -1) {
			if (mkdir(dst, 0766) == -1) {
				perror("mkdir error");
				exit(1);
			}
		}
		char fullpath_src[BUFSIZE];
		char fullpath_dst[BUFSIZE];
		struct dirent *entry;
		while ((entry = readdir(dir)) != NULL) {
			if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) continue;
			sprintf(fullpath_src, "%s/%s", src, entry->d_name);
			sprintf(fullpath_dst, "%s/%s", dst, entry->d_name);
			if (entry->d_type & DT_DIR) {
				copy(fullpath_src, fullpath_dst);
			} else {
				copyfile(fullpath_src, fullpath_dst);
			}
		}

	}

}

void Progress()
{
    int i=0;
    char buf[102];
    memset(buf,'\0',sizeof(buf));
    const char* lable="|/-\\";
    while(i<=100)
    {
        printf("[%-101s][%d%%][%c]\r",buf,i,lable[i%4]);
        fflush(stdout);
        buf[i]='=';
        i++;
        usleep(10000);
        }
        printf("\n");
}


//*****
//删除文件
void del_file(char *path)
{
	if (remove(path) == -1) {
		perror("remove error");
		exit(1);
	}
}

//删除目录
void del_dir(char *path) {
	DIR *dir = opendir(path);
	if (dir == NULL) {
		perror("opendir error");
		exit(1);
	}
	struct dirent *entry;
	char fullpath[BUFSIZE];
	while ((entry = readdir(dir)) != NULL) {
		if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) continue;
		sprintf(fullpath, "%s/%s", path, entry->d_name);
		if (entry->d_type & DT_DIR) {
			del_dir(fullpath);
		} else {
			remove(fullpath);
		}
	}
	closedir(dir);
	remove(path);
}

//*****

//比较函数
int comp(const void *a, const void *b)
{
	struct fileNode *aa = (struct fileNode *)a;
	struct fileNode *bb = (struct fileNode *)b;
	return strcmp(aa->filename, bb->filename);
}

//实现src目录及其文件备份到dst目录下

void copysrc_to_dst(char *src, char *dst)
{
	flag = 1;
	copy(src, dst);
}

//实现两个目录内容的同步1,2
//获取目录下的文件名,这里假设path1是目标文件，path2是原文件
void dir_traverse(char *path1, char *path2) {
	DIR *dir1 = opendir(path1);
	if (dir1 == NULL) {
		perror("opendir error");
		exit(1);
	}
	struct dirent *entry1;
	struct dirent *entry2;
	DIR *dir2 = opendir(path2);
	if (dir2 == NULL) {
		perror("opendir error");
		exit(1);
	}
	struct stat sb;
	struct tm *time;
	struct fileNode fa[BUFSIZE];
	struct fileNode fb[BUFSIZE];
	int k1 = 0;
	int k2 = 0;
	while ((entry1 = readdir(dir1)) != NULL) {
		if (strcmp(".", entry1->d_name) == 0 || strcmp("..", entry1->d_name) == 0) continue;
		strcpy(fa[k1].filename, entry1->d_name);
		lstat(fa[k1].filename, &sb);
		time = gmtime(&sb.st_atime);
		strftime(fa[k1].time, TSIZE, "%Y-%m-%d-%H-%M-%S", time);
		if (entry1->d_type & DT_DIR) fa[k1++].fileType = 1;
		else fa[k1++].fileType = 0;
	}
	while ((entry2 = readdir(dir2)) != NULL) {
		if (strcmp(".", entry2->d_name) == 0 || strcmp("..", entry2->d_name) == 0) continue;
		strcpy(fb[k2].filename, entry2->d_name);
		lstat(fb[k2].filename, &sb);
		time = gmtime(&sb.st_atime);
		strftime(fb[k2].time, TSIZE, "%Y-%m-%d-%H-%M-%S", time);
		if (entry2->d_type & DT_DIR) fb[k2++].fileType = 1;
		else fb[k2++].fileType = 0;
	}
	qsort(fa, k1, sizeof(fa[0]), comp);
	qsort(fb, k2, sizeof(fb[0]), comp);
	int p1 = 0, p2 = 0;
	char fullpath_src[BUFSIZE]; //全路径
	char fullpath_dst[BUFSIZE];
	char fullpath[BUFSIZE];
	while (p1 < k1 && p2 < k2) {
		if (strcmp(fa[p1].filename, fb[p2].filename) > 0) {
			sprintf(fullpath_src, "%s/%s", path2, fb[p2].filename);
			sprintf(fullpath_dst, "%s/%s", path1, fb[p2].filename);
			flag = fb[p2++].fileType;
			copy(fullpath_src, fullpath_dst);
		} else if (strcmp(fa[p1].filename, fb[p2].filename) < 0) {
			sprintf(fullpath, "%s/%s", path1, fa[p1].filename);
			if (fa[p1++].fileType == 1) {
				del_dir(fullpath);
			} else {
				del_file(fullpath);
			}	
		} else if (fa[p1].fileType == 1 && fb[p2].fileType == 1) { //两个文件名相同，是目录
			sprintf(fullpath_src, "%s/%s", path2, fb[p2++].filename);
			sprintf(fullpath_dst, "%s/%s", path1, fa[p1++].filename);
			dir_traverse(fullpath_dst, fullpath_src);

		} else {	//两个文件名相等，算法处理
			if (strcmp(fa[p1].time, fb[p2].time) < 0) {
				sprintf(fullpath_src, "%s/%s", path2, fb[p2].filename);
				sprintf(fullpath_dst, "%s/%s", path1, fb[p2].filename);
				copyfile(fullpath_src, fullpath_dst);
			}
			p1++; p2++;
		}
	}

	while (p1 < k1) { //删除
		sprintf(fullpath, "%s/%s", path1, fa[p1].filename);
		if (fa[p1++].fileType == 1) {
			del_dir(fullpath);
		} else {
			del_file(fullpath);
		}
	}

	while (p2 < k2) { //拷贝
		sprintf(fullpath_src, "%s/%s", path2, fb[p2].filename);
		sprintf(fullpath_dst, "%s/%s", path1, fb[p2].filename);
		flag = fb[p2++].fileType;
		copy(fullpath_src, fullpath_dst);
	}
	
}

